package factory;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

/**
 * @author Steve
 * The Loadable menu is the "top menu" and it loops the the "getOrder"
 * across all items until you select the special item named "Finish Order"
 * 
 * Basically the Menu Factory that is also a singleton
 */
public class LoadableMenu{
	private static String MENU_LOCATION = "resources/menu";	

	/**
	 * Sets config file name
	 * @param filename name of config file
	 */
	public static void setFilename(String filename){
		MENU_LOCATION = filename; 
	}

	protected final String name;
	protected final double price;
	protected final boolean display;
	protected final ArrayList<LoadableMenu> options;

	/**
	 * @param args
	 * @param input
	 */
	protected LoadableMenu(LinkedList<String> args, Scanner input){
		name = args.pop();
		price = new Double(args.pop());
		display = new Boolean(args.pop());
		options = new ArrayList<LoadableMenu>();

		if(args.size() > 0) // this means there is a semicolin, and no sub menu
			return;

		// if there is a sub menu, then load it

		LoadableMenu next;
		while((next = LoadableMenu.load(input)) != null)
			options.add(next);
	}

	/**
	 * @param in
	 * @return OrderObject
	 */
	public OrderObject getOrder(Scanner in){
		LinkedList<OrderObject> orders = new LinkedList<OrderObject>();

		ArrayList<String> choices = new ArrayList<String>();
		for(LoadableMenu lm : options)
			choices.add(lm.name);

		if(!name.equalsIgnoreCase("Your Order Is:") && !name.equalsIgnoreCase("Finish Order"))
			System.out.println("\nSelecting a " + name);

		while(true){
			System.out.println("\nPlease select the next option.");
			int selection = presentMenu(choices, in);

			// keep going until we select "Finish Order"
			if(options.get(selection).name.equals("Finish Order"))
				break;

			if(!name.equalsIgnoreCase("Your Order Is:"))
				System.out.println("\nSelecting a " + options.get(selection).name);

			orders.add(options.get(selection).getOrder(in)); // getSelection
		}	
		return new OrderObject(name, price, display, orders.toArray(new OrderObject[orders.size()]));
	}

	private static LoadableMenu theMenu = null;

	/**
	 * @return instance of LoadableMenu class
	 */
	public static LoadableMenu getInstance(){
		if(theMenu == null) {
			try {
				Scanner input = new Scanner(new File(MENU_LOCATION));

				theMenu = LoadableMenu.load(input);

				input.close();
			} catch(Throwable t){ 
				t.printStackTrace(); 
				System.err.println("FATAL: Could not load config file " + MENU_LOCATION + " - Exiting..."); 
				System.exit(-1); 
			}
		}
		return theMenu;
	}

	/**
	 * @param input line from config file
	 * @return which menu to use
	 */
	protected static LoadableMenu load(Scanner input){
		LinkedList<String> args = new LinkedList<String>();
		for(String arg : input.nextLine().trim().split(","))
			args.add(arg);

		String clazz = args.pop();

		// menu items
		if(clazz.equals("RM")){
			return new RequiredMenu(args, input);
		}
		else if(clazz.equals("I")){
			return new ItemMenu(args, input);
		} 
		else if(clazz.equals("LL")){
			return new LoadableMenu(args, input);
		}
		return null;
	}

	/**
	 * @param choices menu list of choices
	 * @param in
	 * @return current menu choice
	 */
	protected int presentMenu(List<String> choices, Scanner in){
		StringBuffer sb = new StringBuffer();

		for(int i=0; i<choices.size(); i++)
			sb.append(i).append(") ").append(choices.get(i)).append("\n");

		int choice = -1;
		boolean first = true;
		while(choice == -1){
			if(!first)
				System.out.println("\nThis is not a valid choice, try again.\n");
			first = false;

			System.out.println(sb.toString());

			try{
				choice = Integer.parseInt(in.nextLine());
			} catch (NumberFormatException nfe) {
				choice = -1;
			}
			if(choice < 0 || choice >= choices.size())
				choice = -1;
		}
		return choice;
	}
}
